package com.matto1990.app.madlab.ui;

import java.util.ArrayList;
import java.util.List;

import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;

import com.matto1990.app.madlab.R;
import com.matto1990.app.madlab.provider.MadlabContract.Events;
import com.matto1990.app.madlab.util.NotifyingAsyncQueryHandler;
import com.matto1990.app.madlab.util.Pair;
import com.matto1990.app.madlab.util.TitlebarActivity;
import com.matto1990.app.madlab.util.NotifyingAsyncQueryHandler.AsyncQueryListener;

public class EventsActivity extends TitlebarActivity implements AsyncQueryListener {
    public static final String TAG = "Madlab";
    private ListView list;
    private EventsAdapter adapter;
    private NotifyingAsyncQueryHandler handler;
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // Set the layout
        setContentView(R.layout.activity_events);
        
        // Setup the title bar UI
        setupTitlebar();
        
        getApplicationContext();
        final Uri eventsUri = Events.CONTENT_URI;
        
        // Get the list and set its adapter
        list = (ListView) findViewById(R.id.events_list);
        adapter = new EventsAdapter();
        list.setAdapter(adapter);
        list.setOnItemClickListener(itemClickListener);
        
        // Start background query to load events
        handler = new NotifyingAsyncQueryHandler(getContentResolver(), this);
        handler.startQuery(eventsUri, EventsQuery.PROJECTION, Events.DEFAULT_SORT);
    }
    
    // Run when the query on the content uri is returned
    /** {@inheritDoc} */
    @Override
    public void onQueryComplete(int token, Object cookie, Cursor cursor) {
        // Start managing the cursor and set our adapter to use it
        // FIXME: Problem with cursor not being closed by the activity
        startManagingCursor(cursor);
        adapter.changeCursor(cursor);
    }

    /** {@inheritDoc} */
    private OnItemClickListener itemClickListener = new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            // Get the item from the cursor in this position
            final Cursor cursor = (Cursor) adapter.getItem(position);
            // Get the event id
            final String eventId = cursor.getString(cursor.getColumnIndex(Events.EVENT_ID));
            // Build a url for that specific event
            final Uri eventUri = Events.buildEventUri(eventId);
            // Make an intent to launch that uri
            final Intent intent = new Intent(Intent.ACTION_VIEW, eventUri);
            // Send the state
            intent.putExtra(STATE, state);
            // Start the activity
            startActivity(intent);
        }
    };
    
    /**
     * An adapter designed to take and events cursor and show it in a list
     * @author oakesm9
     */
    private class EventsAdapter extends BaseAdapter {
        // The list of data as a pair. The first element is true if data and the second is the position of either the separator or the data in the respective list/cursor
        private List<Pair<Boolean, Integer>> dataList; 
        // The cursor to use
        private Cursor cursor;
        // The separator list
        private List<Character> separatorList;
        
        /**
         * Constructor to use if no cursor is yet available
         */
        public EventsAdapter() {
            dataList = new ArrayList<Pair<Boolean, Integer>>();
            separatorList = new ArrayList<Character>();
        }
        /**
         * Constructor when a cursor has already been got
         * @param requiredCursor The cursor to use
         */
        public EventsAdapter(Cursor requiredCursor) {
            // Run the other constructor
            this();
            // Assign the cursor
            cursor = requiredCursor;
            // Populate the other lists
            populateLists();
        }
        
        /**
         * Changes the cursor and notifies that the data has changed
         * @param requiredCursor The new cursor
         */
        public void changeCursor(Cursor requiredCursor) {
            // Change the cursor
            cursor = requiredCursor;
            // Populate the lists
            populateLists();
            // Notify anyone interested that the data has now changed
            notifyDataSetChanged();
        }
        
        /**
         * Populates the separator list and the data list given the contents of the cursor member variable
         */
        private void populateLists() {
            // Reset all of the lists other than the cursor
            dataList.clear();
            separatorList.clear();
            
            // Setup some variable to be used in a loop
            Character lastSeparatorChar = null;
            Character currentChar;
            
            // Move the cursor to the first position
            cursor.moveToFirst();
            // Loop through all items in the cursor
            while (!cursor.isAfterLast()) {
                // Get the first letter of the current cursor position
                currentChar = cursor.getString(cursor.getColumnIndex(Events.EVENT_TITLE)).charAt(0);
                
                // Check if the character is different
                if (!currentChar.equals(lastSeparatorChar)) {
                    // Add a new separator element
                    separatorList.add(currentChar);
                    // Add a new pointer in the data list to the new separator
                    dataList.add(new Pair<Boolean, Integer>(false, separatorList.indexOf(currentChar)));
                    // Set the last separator char
                    lastSeparatorChar = currentChar;
                }
                
                // Add a pointer in the data list to the actual data
                dataList.add(new Pair<Boolean, Integer>(true, cursor.getPosition()));
                
                // Move to the next item in the cursor
                cursor.moveToNext();
            }
        }
        
        /**
         * Get the number of items in this adapter
         */
        @Override
        public int getCount() {
            return dataList.size();
        }
        
        /**
         * Returns a cursor which is already pointed at the correct position
         */
        @Override
        public Object getItem(int position) {
            // Get the data pair
            final Pair<Boolean, Integer> dataPair = dataList.get(position);
            // Check if the dataPir is data
            if (dataPair.first) {
                // If so, move to the position given by the second element
                cursor.moveToPosition(dataPair.second);
                return cursor;
            }
            else {
                // If not it's a separator and we should return null
                return null;
            }
        }
        
        /**
         * Always returns true to show that id's are stable
         */
        @Override
        public boolean hasStableIds() {
            return true;
        }
        
        /**
         * Get the id of an item of given position 
         */
        // TODO: This method is no guaranteed to return a unique id but it will be stable
        @Override
        public long getItemId(int position) {
            // Get the data pair
            final Pair<Boolean, Integer> dataPair = dataList.get(position);
            // Check if the dataPir is data
            if (dataPair.first) {
                // If so, move to the position given by the second element
                cursor.moveToPosition(dataPair.second);
                
                // Get the byte array of the event id
                final byte[] bytes = cursor.getString(cursor.getColumnIndex(Events.EVENT_ID)).getBytes();
                
                // Loop through the bytes in the array
                long theTotal = 0;
                for (byte theByte : bytes) {
                    // Add the int value of that byte to the total long
                    theTotal += new Integer(theByte).intValue();
                }
                
                // Return the total long value as a (possibly) unique id
                return theTotal;
            }
            else {
                // If not it's a separator and we should return 0
                return 0;
            }
        }
        
        /**
         * Returns false to show we have some separators
         */
        @Override
        public boolean areAllItemsEnabled() {
            return false;
        }
        
        /**
         * Returns true if the item at the specified position is not a separator.
         */
        @Override
        public boolean isEnabled(int position) {
            // Get the data pair
            final Pair<Boolean, Integer> dataPair = dataList.get(position);
            // If first is true then the data pair contains data (not not a separator) and should be enabled
            return dataPair.first;
        }
        
        /**
         * Returns the number of different views
         */
        @Override
        public int getViewTypeCount() {
            return 2;
        }
        
        @Override
        public int getItemViewType(int position) {
            // Get the data pair
            final Pair<Boolean, Integer> dataPair = dataList.get(position);
            // Return 0 if it is normal data
            if (dataPair.first) {
                return 0;
            }
            // Return 1 if it's a separator
            else {
                return 1;
            }
        }
        
        /**
         * Get the view ready to display
         */
        // TODO: Use the view holder pattern to speed up this code
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // Get the data pair
            final Pair<Boolean, Integer> dataPair = dataList.get(position);
            
            // Check if the view is a data view
            if (dataPair.first) {
                // Check if we have been given a view already
                if (convertView == null) {
                    // If not inflate one
                    convertView = getLayoutInflater().inflate(R.layout.list_item_event, parent, false);
                }
                
                // Move the cursor to the right position
                cursor.moveToPosition(dataPair.second);
                
                // Get the event title view
                final TextView titleView = (TextView) convertView.findViewById(R.id.event_title);
                // Set the text for the event title
                titleView.setText(cursor.getString(cursor.getColumnIndex(Events.EVENT_TITLE)));
                
                // Check if the user is interested
                final boolean interested = cursor.getInt(cursor.getColumnIndex(Events.EVENT_INTERESTED)) == 1;
                if (interested) {
                    // If so set the interested background
                    convertView.setBackgroundResource(R.color.event_interested_background);
                }
                else {
                    // If not set the default one
                    // TODO: There is a problem with loosing focus and click states from here
                    convertView.setBackgroundResource(android.R.color.background_light);
                }
            }
            // If not it must be a separator
            else {
                // Check if we have been given a view already
                if (convertView == null) {
                    // If not inflate one
                    convertView = getLayoutInflater().inflate(R.layout.list_item_separator, parent, false);
                }
                
                // Get the separator text view
                final TextView view = (TextView) convertView.findViewById(R.id.separator);
                // Set the view text
                view.setText(separatorList.get(dataPair.second).toString());
            }
            
            return convertView;
        }
        
    }
    
    /** {@link Events} query parameters. */
    private interface EventsQuery {
        String[] PROJECTION = {
                BaseColumns._ID,
                Events.EVENT_ID,
                Events.EVENT_TITLE,
                Events.EVENT_INTERESTED
        };
    }
}
